#ifndef _EIX_PRIVATE_H
#define _EIX_PRIVATE_H

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <string.h>
#include <unistd.h>

#define ERR(...) EINA_LOG_DOM_ERR(eix_log, __VA_ARGS__)
#define INF(...) EINA_LOG_DOM_INFO(eix_log, __VA_ARGS__)
#define WRN(...) EINA_LOG_DOM_WARN(eix_log, __VA_ARGS__)
#define DBG(...) EINA_LOG_DOM_DBG(eix_log, __VA_ARGS__)

extern int eix_log;

typedef void (*Eix_Transport_Add)(Eix_Transport *end, void *user_data);
typedef void (*Eix_Transport_Remove)(void *user_data);
typedef void (*Eix_Transport_Data)(Eix_Message *m, void *body, void *reply,
		Eix_Error *error, void *user_data);

typedef struct _Eix_Transport_Process_Descriptor
{
	Eix_Transport_Add add;
	Eix_Transport_Remove remove;
	Eix_Transport_Data data;
} Eix_Transport_Process_Descriptor;

typedef enum _Eix_Transport_Status
{
	EIX_TRANSPORT_STATUS_FAILED,
	EIX_TRANSPORT_STATUS_OK,
	EIX_TRANSPORT_STATUS_ASYNC,
	EIX_TRANSPORT_STATUS,
} Eix_Transport_Status;

typedef void (*Eix_Transport_Free)(void *data);
typedef Eix_Transport_State (*Eix_Transport_Serve)(void *data);
typedef Eix_Transport_State (*Eix_Transport_Connect)(void *data);
typedef Eix_Transport_Status (*Eix_Transport_Send)(void *data,
		void *buf, size_t *len);
typedef Eix_Transport_Status (*Eix_Transport_Recv)(void *data,
		void *buf, size_t *len);
typedef Eina_Bool (*Eix_Transport_Wait)(void *data);

typedef struct _Eix_Transport_Descriptor
{
	Eix_Transport_Free free;
	Eix_Transport_Serve serve;
	Eix_Transport_Connect connect;
	Eix_Transport_Recv recv;
	Eix_Transport_Send send;
	Eix_Transport_Wait wait_read;
	Eix_Transport_Wait wait_write;
} Eix_Transport_Descriptor;

Eina_Bool eix_transport_posix_wait_write(int fd);
Eina_Bool eix_transport_posix_wait_read(int fd);

typedef Eix_Transport_State (*Eix_Transport_Process)(void *data,
		Eix_Transport_State state,
		Eina_Bool can_read,
		Eina_Bool can_write);


Eix_Transport * eix_transport_new(Eix_Transport_Descriptor *d, void *data);
void eix_transport_free(Eix_Transport *thiz);
void * eix_transport_data_get(Eix_Transport *thiz);

Eina_Bool eix_transport_connect(Eix_Transport *thiz);
Eina_Bool eix_transport_serve(Eix_Transport *thiz);
void eix_transport_state_set(Eix_Transport *thiz, Eix_Transport_State state);

/* Function to be called from the upper layer of the transports */
void eix_transport_process_descriptor_set(Eix_Transport *thiz,
		Eix_Transport_Process_Descriptor *descriptor,
		void *user_data);
Eina_Bool eix_transport_send(Eix_Transport *t, Eix_Message *m,
		uint32_t rid, void *data, void *rdata, Eix_Error *err,
		uint32_t *id, Eix_Transport_Reply_Cb cb, const void *user_data);
void eix_transport_process(Eix_Transport *thiz, Eina_Bool can_read,
		Eina_Bool can_write);
Eina_Bool eix_transport_flush(Eix_Transport *thiz);
Eina_Bool eix_transport_sync(Eix_Transport *thiz);
/* Functions called from the transport implementations */
void eix_transport_process_add(Eix_Transport *thiz, Eix_Transport *c);
Eina_Bool eix_transport_recv(Eix_Transport *thiz);
void eix_transport_process_request(Eix_Transport *thiz, Eina_Bool to_read,
		Eina_Bool to_write);
void eix_transport_process_set(Eix_Transport *thiz,
		Eix_Transport_Process process);

typedef enum _Eix_Message_Sync_Type
{
	EIX_MESSAGE_SYNC 	= 0,
	EIX_MESSAGE_ASYNC 	= 1,
	EIX_MESSAGE_SYNC_TYPES,
} Eix_Message_Sync_Type;

typedef enum _Eix_Message_Reply_Type
{
	EIX_MESSAGE_NO_REPLY 	= 0,
	EIX_MESSAGE_REPLY 	= 1,
	EIX_MESSAGE_REPLY_TYPES,
} Eix_Message_Reply_Type;

typedef enum _Eix_Message_Type
{
	EIX_MESSAGE_SIGNAL 	= (EIX_MESSAGE_NO_REPLY << 1),
	EIX_MESSAGE_REPLY_SYNC	= (EIX_MESSAGE_REPLY << 1) | (EIX_MESSAGE_SYNC),
	EIX_MESSAGE_REPLY_ASYNC	= (EIX_MESSAGE_REPLY << 1) | (EIX_MESSAGE_ASYNC),
	EIX_MESSAGE_TYPES,
} Eix_Message_Type;

/* Add a struct for the error so user will know how to send errors */
/* eix_server_send_error(Eix_Server *s, const char *str); */

struct _Eix_Message
{
	unsigned int id;
	Eix_Message_Type type;
	double timeout;
	Ender_Descriptor *edd;
	Eix_Message *reply;
};

Eix_Message * eix_message_find(int id);

void eix_message_init(void);
void eix_message_shutdown(void);

struct _Eix_Server
{
	Eix_Transport *t;
	Eix_Server_Descriptor *descriptor;
	void *data;
	Eina_Hash *user_data;
	Eina_List *clients;
	Eina_Bool delete_me;
};

void eix_server_client_remove(Eix_Server *thiz, Eix_Client *cl);

struct _Eix_Client
{
	Eix_Transport *t;
	Eix_Server *server;
	Eina_Hash *user_data;
	Eina_Bool delete_me;
};

Eix_Client * eix_client_new(Eix_Transport *t, Eix_Server *srv);

#endif
